package com.huan.es8;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * es8 api
 *
 * <a href="https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/installation.html">https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/installation.html</a>
 *
 * @author huan.fu
 * @date 2022/10/31 - 23:22
 */
public abstract class AbstractEs8Api {

    /**
     * es8 client
     */
    protected ElasticsearchClient client;

    protected AbstractEs8Api() {
        // es username password
        final CredentialsProvider credentialsProvider =
                new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials("elastic", "elastic"));

        // Create the low-level client
        RestClient restClient = RestClient.builder(
                        new HttpHost("192.168.121.138", 9200, "https"))
                .setHttpClientConfigCallback(httpAsyncClientBuilder ->
                        {
                            try {
                                return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                                        .setSSLContext(createSslContext());
                            } catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException |
                                     KeyManagementException e) {
                                throw new RuntimeException(e);
                            }
                        }
                )
                .build();

        // Create the transport with a Jackson mapper
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper());

        // And create the API client
        client = new ElasticsearchClient(transport);
    }

    private SSLContext createSslContext() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        // es 的证书
        Path caCertificatePath = Paths.get("/Users/huan/code/IdeaProjects/me/spring-cloud-parent/es/es8-api/src/main/resources/http_ca.crt");

        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        Certificate trustedCa;
        try (InputStream is = Files.newInputStream(caCertificatePath)) {
            trustedCa = factory.generateCertificate(is);
        }
        KeyStore trustStore = KeyStore.getInstance("pkcs12");
        trustStore.load(null, null);
        trustStore.setCertificateEntry("ca", trustedCa);
        SSLContextBuilder sslContextBuilder = SSLContexts.custom()
                .loadTrustMaterial(trustStore, null);
        return sslContextBuilder.build();
    }

    /**
     * 创建搜索
     *
     * @param indexName 索引名
     * @param json      index mappings 等
     * @throws IOException
     */
    protected void createIndex(String indexName, String json) throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder()
                .index(indexName)
                .withJson(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)))
                .build();
        System.err.println("createIndexRequest: " + createIndexRequest);
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest);
        System.err.println("createIndexResponse: " + createIndexResponse);
    }

    /**
     * 删除索引
     *
     * @param indexName 索引名
     * @throws IOException 异常
     */
    protected void deleteIndex(String indexName) throws IOException {
        DeleteIndexResponse deleteIndexResponse = client.indices()
                .delete(request -> request.index(indexName));
        System.out.println(deleteIndexResponse);
    }

    protected void bulk(String indexName,List<String> documents) throws IOException {

        List<BulkOperation> bulkOperations  = new ArrayList<>(3);

        ObjectMapper objectMapper = new ObjectMapper();

        for (String document : documents) {
            BulkOperation bulkOperation = BulkOperation.of(operation ->
                    operation.create(create -> {
                        try {
                            return create.index(indexName).document(objectMapper.readValue(document, Map.class));
                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                            throw new RuntimeException(e);
                        }
                    }));
            bulkOperations.add(bulkOperation);
        }

        BulkResponse bulkResponse = client.bulk(builder -> builder.operations(bulkOperations));
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(bulkResponse);
    }
}
